﻿using System;
using System.ServiceModel;
using System.Threading;
using Airborne.ScrumPoker.Communication;
using Airborne.ScrumPoker.Module.Events;
using Airborne.ScrumPoker.Module.Host.Services;

namespace Airborne.ScrumPoker.Module.Host.Model
{
    /// <summary>
    /// Represents a connection from the client.
    /// </summary>
    /// <remarks>
    /// TODO: Need to look at using WCF to do async callbacks to the client.
    /// </remarks>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class ScrumPokerClientConnection : IScrumPokerClientConnection
    {
        #region Members
        delegate void StartTimerDelegate(int seconds);

        private AsyncCallback threadNullCallBackTarget;
        #endregion

        #region Constructors
        public ScrumPokerClientConnection()
        {
            threadNullCallBackTarget = new AsyncCallback(ThreadNullCallBack);
        }
        #endregion

        #region Events

        #region Voted

        public event EventHandler<GenericEventArgs<double>> Voted;

        private void RaiseVote(double vote)
        {
            GenericEventArgs<double> args = new GenericEventArgs<double>(vote);
            OnVote(args);
        }

        protected virtual void OnVote(GenericEventArgs<double> args)
        {
            EventHandler<GenericEventArgs<double>> handler = this.Voted;
            if (handler != null)
            {
                handler(this, args);
            }
        }

        #endregion

        #endregion

        #region Properties
        public string ClientName { get; set; }
        private IScrumPokerCallback ClientCallback { get; set; }

        #endregion

        #region IScrumPokerServer Members
        public bool Subscribe(string clientName)
        {
            ClientName = clientName;
            if (ConnectionManager.Instance.CanRegister(this))
            {
                ConnectionManager.Instance.Register(this);
                ClientCallback = OperationContext.Current.GetCallbackChannel<IScrumPokerCallback>();
                return true;
            }
            else
            {
                return false;
            }

        }

        public void Unsubscribe()
        {
            ConnectionManager.Instance.Unregister(this);
        }

        public void Vote(double cardValue)
        {
            RaiseVote(cardValue);
        }


        public void StartTimer(int seconds)
        {
            StartTimerDelegate start = new StartTimerDelegate(ClientCallback.TimerStarted);
            start.BeginInvoke(seconds, threadNullCallBackTarget, this);
        }

        private void ThreadNullCallBack(IAsyncResult result)
        {
        }

        public void StopTimer()
        {
            ThreadStart thread = new ThreadStart(ClientCallback.TimerStopped);
            thread.BeginInvoke(threadNullCallBackTarget, this);
        }

        public void SelectWorkItem(string title, string description)
        {
            ClientCallback.SelectWorkItem(title, description);
        }

        public void ResetVote()
        {
            ThreadStart thread = new ThreadStart(ClientCallback.ResetVote);
            thread.BeginInvoke(threadNullCallBackTarget, this);
        }

        public void EndGame()
        {
            ThreadStart thread = new ThreadStart(ClientCallback.GameEnded);
            thread.BeginInvoke(threadNullCallBackTarget, this);
        }
        #endregion

    }
}
